package com.liruo.treasureattic.common.util.crypto;

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;

import java.security.KeyPair;

/**
 * @Author:liruo
 * @Date:2022-10-23-16:57:46
 * @Desc
 * hutool使用注意
 *  decrypt 对普通字节解密
 *  decryptStr  是对base64字符串解密
 *  encrypt     是对某种字符串加密
 *  encryptBase64 是对某个字符串加密，但是返回一个base64字符串
 *
 *  使用base64
 *      应该 encryptBase64 decryptStr   不用对字符串做任何编码上的修改，就原本字符串就可以了
 *  对于private和public的key或者就只是一个key，都使用base64进行保存
 *
 *  key都是从加密处生成的，因此生成key时，都用普通字符串传入，方法内部用base64编码key
 *  获取的key，都是一个base64字符串
 *  对content的加密解密都使用base64即encryptBase64和decryptStr，content就传字符串不用该编码
 *
 */
public class CryptoUtil {
    //比较安全的size，256已经被破解
    public static final int KEY_SIZE  =2048;

    /**
     * 生成AES对称加密
     * @param key 密匙，普通字符串，自动转为base64
     * @return
     */
    public static AES generateAesCBCByKey(String key){
        return new AES(
                Mode.CBC,
                Padding.PKCS5Padding,
                //key==new String(aes.getSecretKey().getEncoded())
                Base64.encode(key).getBytes()
        );
    }

    /**
     * 从一个base64的密匙获取一个AES对称加密，不是生成，生成用{@link CryptoUtil#generateAesCBCByKey}
     * @param keyBase64  从配置获取到的密匙，base64字符串
     * @return
     */
    public static AES getAesCBCByBase64Key(String keyBase64){
        return new AES(
                Mode.CBC,
                Padding.PKCS5Padding,
                //key==new String(aes.getSecretKey().getEncoded())
                keyBase64.getBytes()
        );
    }

    /**
     *
     * @param aes
     * @return base64的密匙
     */
    public static String getKeyBase64(AES aes){
        return new String(aes.getSecretKey().getEncoded());
    }

    /**
     * 传入base64的content进行解密，返回一个原本的字符串
     */
    public static String decryptBase64AesCBC(String keyBase64, String base64){
        return getAesCBCByBase64Key(keyBase64).decryptStr(base64);
    }
    /**
     * 传入base64的content进行解密，返回一个原本的字符串
     * 保存了AES对象
     */
    public static String decryptBase64AesCBC(AES aes, String base64){
        return aes.decryptStr(base64);
    }

    /**
     * 传入原本的字符串进行加密，加密后返回一个base64的加密字符串
     */
    public static String encryptToBase64AesCBC(String keyBase64, String content){
        return getAesCBCByBase64Key(keyBase64).encryptBase64(content);
    }
    /**
     * 传入原本的字符串进行加密，加密后返回一个base64的加密字符串
     * 保存了AES对象
     */
    public static String encryptToBase64AesCBC(AES aes, String content){
        return aes.encryptBase64(content);
    }

    /**
     * 生成一个RSA非对称加密，公私匙都是随机的
     * 默认RSA 是就 RSA/ECB/PKCS1Padding
     * @return
     */
    public static RSA generateRsa(){
        KeyPair rs256 = SecureUtil.generateKeyPair(AsymmetricAlgorithm.RSA.getValue(), KEY_SIZE);
        return new RSA(rs256.getPrivate(),rs256.getPublic());
    }

    /**
     *
     * @param privateKeyBase64  从配置获取到的privateKeyBase64
     * @param publicKeyBase64   从配置获取到的publicKeyBase64
     * @return
     */
    public static RSA getRsaByBase64(String privateKeyBase64, String publicKeyBase64){
        return new RSA(
                AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue(),
                privateKeyBase64,
                publicKeyBase64
        );
    }

    /**
     *
     * @param rsa
     * @return RSA的公匙---base64编码的
     */
    public static String getRsaPublicKeyBase64(RSA rsa){
        return rsa.getPublicKeyBase64();
    }
    /**
     *
     * @param rsa
     * @return RSA的私匙---base64编码的
     */
    public static String getRsaPrivateKeyBase64(RSA rsa){
        return rsa.getPrivateKeyBase64();
    }

    /**
     * 传入base64的content进行解密，返回一个原本的字符串
     * 保存了RSA对象
     */
    public static String decryptBase64Rsa(RSA rsa,String base64){
        return rsa.decryptStr(base64, KeyType.PrivateKey);
    }
    /**
     * 传入base64的content进行解密，返回一个原本的字符串
     */
    public static String decryptBase64Rsa(String privateKeyBase64,String base64){
        return getRsaByBase64(privateKeyBase64,null)
                .decryptStr(base64, KeyType.PrivateKey);
    }

    /**
     * 传入原本的字符串进行加密，加密后返回一个base64的加密字符串
     * 保存了RSA对象
     */
    public static String encryptToBase64Rsa(RSA rsa,String content){
        return rsa.encryptBase64(content, KeyType.PublicKey);
    }
    /**
     * 传入原本的字符串进行加密，加密后返回一个base64的加密字符串
     */
    public static String encryptToBase64Rsa(String publicKeyBase64,String content){
        return getRsaByBase64(null,publicKeyBase64)
                .encryptBase64(content, KeyType.PublicKey);
    }
}
